import sys
from PyQt6.QtWidgets import QApplication, QMainWindow
from PyQt6.QtCore import pyqtSignal, QUrl
from sls_mqttClient import MQTTClient
from main_window_ui import Ui_MainWindow
from PyQt6.QtWebEngineWidgets import QWebEngineView
from PyQt6.QtWebChannel import QWebChannel
import io
import folium
import json

# 镇江的江苏大学的经纬度119.515293, 32.199403
default_latitude = 32.199403
default_longitude = 119.515293

class GCMainWindow(QMainWindow):
    statusBar_signal = pyqtSignal(str)
    mapUpdate_signal = pyqtSignal(float, float)
    def __init__(self):
        super().__init__()

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.mqtt_client = MQTTClient()
        self.mqtt_client.connect()
        self.mqtt_client.set_connect_handle_callback(self.mqtt_connect_handle_callback)
        self.mqtt_client.set_message_handle_callback(self.mqtt_message_handle_callback)

        self.statusBar_signal.connect(self.ui.statusbar.showMessage)
        self.ui.statusbar.showMessage("mqtt连接中...")

        # 创建 QWebEngineView 并添加到布局中
        self.web_view = QWebEngineView()
        self.ui.verticalLayout.addWidget(self.web_view)
        self.generate_map()
        self.mapUpdate_signal.connect(self.map_update)

    def map_update(self, latitude, longitude):
        js_code = f"""
        window.updateMarkerPosition({latitude}, {longitude});
        """
        self.web_view.page().runJavaScript(js_code)

    def mqtt_message_handle_callback(self, client, userdata, msg):
        topic = msg.topic
        message = msg.payload.decode()
        self.statusBar_signal.emit(f"收到消息：{topic} {message}")
        if topic == "/status/fly1/PR":
            messageDict = json.loads(message)
            gnss_position = messageDict["GNSS_position"]
            latitude = gnss_position["latitude"]
            longitude = gnss_position["longitude"]
            self.mapUpdate_signal.emit(latitude, longitude)
            self.statusBar_signal.emit(f"更新地图：{latitude} {longitude}")

    def mqtt_connect_handle_callback(self, client, userdata, flags, rc):
        self.statusBar_signal.emit("mqtt连接成功")
        self.mqtt_client.subscribe_topics(["/status/fly1/PR"])

    def generate_map(self):
        # 创建 folium 地图对象，设置最大缩放级别
        m = folium.Map(location=[default_latitude, default_longitude], zoom_start=18, control_scale=True, max_zoom=22, tiles=None)

        # 添加高德普通地图瓦片
        gaode_normal_tiles = folium.TileLayer(
            tiles='http://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
            attr='高德地图',
            subdomains='1234',
            max_zoom=22,
            name='高德普通地图'
        )
        gaode_normal_tiles.add_to(m)

        # 添加高德卫星地形图瓦片
        gaode_satellite_tiles = folium.TileLayer(
            tiles='http://webst0{s}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}',
            attr='高德地图',
            subdomains='1234',
            max_zoom=22,
            name='高德卫星地形图'
        )
        gaode_satellite_tiles.add_to(m)

        # 添加标记到地图上，并添加自定义属性
        marker = folium.Marker([default_latitude, default_longitude], icon=folium.Icon(color='blue'))
        # 给标记添加自定义属性
        marker.add_to(m)
        marker._id = 'location_marker'

        # 添加图层控制
        folium.LayerControl().add_to(m)

        # 保存地图为 HTML 文件
        data = io.BytesIO()
        m.save(data, close_file=False)
        html_content = data.getvalue().decode()

        # 注入 QWebChannel.js 和必要的样式
        html_content = html_content.replace('</body>', """
        <script>
            // 全局变量，用于保存 Leaflet 地图对象
            var globalMap;

            // 监听 DOM 加载完成事件
            document.addEventListener('DOMContentLoaded', function() {
                // 每隔 100 毫秒检查 Leaflet 地图是否加载完成
                var checkLeaflet = setInterval(function() {
                    // 过滤出所有 Leaflet 地图对象
                    var maps = Object.values(window).filter(function(value) {
                        return value && value._initHooksCalled && value.getContainer;
                    });

                    // 如果找到地图对象，则清除定时器并绑定事件
                    if (maps.length > 0) {
                        clearInterval(checkLeaflet);
                        globalMap = maps[0];

                        // 修改瓦片加载行为，处理所有缩放级别
                        globalMap.eachLayer(function(layer) {
                            if (layer instanceof L.TileLayer) {
                                const maxAvailableZoom = 19; // 地图源最大可用缩放级别
                                layer.createTile = function(coords, done) {
                                    var tile = document.createElement('img');
                                    tile.onerror = L.bind(this._tileOnError, this, done, tile);
                                    tile.crossOrigin = '';

                                    var originalZ = coords.z;
                                    if (originalZ > maxAvailableZoom) {
                                        coords.z = maxAvailableZoom;
                                        var scaleFactor = Math.pow(2, originalZ - maxAvailableZoom);
                                        tile.style.transform = 'scale(' + scaleFactor + ')';
                                        tile.style.transformOrigin = '0 0';
                                    } else {
                                        // 对于小于等于最大可用缩放级别的缩放，正常加载瓦片
                                        coords.z = originalZ;
                                        tile.style.transform = 'scale(1)';
                                    }

                                    var url = this.getTileUrl(coords);
                                    tile.src = url;

                                    return tile;
                                };
                            }
                        });
                    }
                }, 100);
            });
        </script>
        </body>
        """)

        # 设置 baseUrl 以确保可以加载 qwebchannel.js
        self.web_view.setHtml(html_content)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    main_window = GCMainWindow()
    main_window.show()
    sys.exit(app.exec())
    